return err;
}
+int xc_domain_memory_populate_physmap(int xc_handle,
+ uint32_t domid,
+ unsigned long nr_extents,
+ unsigned int extent_order,
+ unsigned int address_bits,
+ unsigned long *extent_start)
+{
+ int err;
+ struct xen_memory_reservation reservation = {
+ .extent_start = extent_start,
+ .nr_extents = nr_extents,
+ .extent_order = extent_order,
+ .address_bits = address_bits,
+ .domid = domid
+ };
+
+ err = xc_memory_op(xc_handle, XENMEM_populate_physmap, &reservation);
+ if ( err == nr_extents )
+ return 0;
+
+ if ( err > 0 )
+ {
+ fprintf(stderr,"Failed deallocation for dom %d: %ld pages order %d\n",
+ domid, nr_extents, extent_order);
+ errno = EBUSY;
+ err = -1;
+ }
+
+ return err;
+}
+
+int xc_domain_translate_gpfn_list(int xc_handle,
+ uint32_t domid,
+ unsigned long nr_gpfns,
+ unsigned long *gpfn_list,
+ unsigned long *mfn_list)
+{
+ struct xen_translate_gpfn_list op = {
+ .domid = domid,
+ .nr_gpfns = nr_gpfns,
+ .gpfn_list = gpfn_list,
+ .mfn_list = mfn_list
+ };
+
+ return xc_memory_op(xc_handle, XENMEM_translate_gpfn_list, &op);
+}
+
int xc_domain_max_vcpus(int xc_handle, uint32_t domid, unsigned int max)
{
DECLARE_DOM0_OP;
DECLARE_HYPERCALL;
struct xen_memory_reservation *reservation = arg;
struct xen_machphys_mfn_list *xmml = arg;
+ struct xen_translate_gpfn_list *trans = arg;
long ret = -EINVAL;
hypercall.op = __HYPERVISOR_memory_op;
goto out1;
}
break;
+ case XENMEM_translate_gpfn_list:
+ if ( mlock(trans, sizeof(*trans)) != 0 )
+ {
+ PERROR("Could not mlock");
+ goto out1;
+ }
+ if ( mlock(trans->gpfn_list, trans->nr_gpfns * sizeof(long)) != 0 )
+ {
+ PERROR("Could not mlock");
+ safe_munlock(trans, sizeof(*trans));
+ goto out1;
+ }
+ if ( mlock(trans->mfn_list, trans->nr_gpfns * sizeof(long)) != 0 )
+ {
+ PERROR("Could not mlock");
+ safe_munlock(trans->gpfn_list, trans->nr_gpfns * sizeof(long));
+ safe_munlock(trans, sizeof(*trans));
+ goto out1;
+ }
+ break;
}
ret = do_xen_hypercall(xc_handle, &hypercall);
case XENMEM_reserved_phys_area:
safe_munlock(arg, sizeof(struct xen_reserved_phys_area));
break;
+ case XENMEM_translate_gpfn_list:
+ safe_munlock(trans->mfn_list, trans->nr_gpfns * sizeof(long));
+ safe_munlock(trans->gpfn_list, trans->nr_gpfns * sizeof(long));
+ safe_munlock(trans, sizeof(*trans));
+ break;
}
out1:
unsigned int extent_order,
unsigned long *extent_start);
+int xc_domain_memory_populate_physmap(int xc_handle,
+ uint32_t domid,
+ unsigned long nr_extents,
+ unsigned int extent_order,
+ unsigned int address_bits,
+ unsigned long *extent_start);
+
+int xc_domain_translate_gpfn_list(int xc_handle,
+ uint32_t domid,
+ unsigned long nr_gpfns,
+ unsigned long *gpfn_list,
+ unsigned long *mfn_list);
+
int xc_domain_ioport_permission(int xc_handle,
uint32_t domid,
uint32_t first_port,
#include <asm/hardirq.h>
#include <public/memory.h>
+/*
+ * To allow safe resume of do_memory_op() after preemption, we need to know
+ * at what point in the page list to resume. For this purpose I steal the
+ * high-order bits of the @cmd parameter, which are otherwise unused and zero.
+ */
+#define START_EXTENT_SHIFT 4 /* cmd[:4] == start_extent */
+
static long
increase_reservation(
struct domain *d,
return nr_extents;
}
-/*
- * To allow safe resume of do_memory_op() after preemption, we need to know
- * at what point in the page list to resume. For this purpose I steal the
- * high-order bits of the @cmd parameter, which are otherwise unused and zero.
- */
-#define START_EXTENT_SHIFT 4 /* cmd[:4] == start_extent */
+static long
+translate_gpfn_list(
+ struct xen_translate_gpfn_list *uop, unsigned long *progress)
+{
+ struct xen_translate_gpfn_list op;
+ unsigned long i, gpfn, mfn;
+ struct domain *d;
+
+ if ( copy_from_user(&op, uop, sizeof(op)) )
+ return -EFAULT;
+
+ /* Is size too large for us to encode a continuation? */
+ if ( op.nr_gpfns > (ULONG_MAX >> START_EXTENT_SHIFT) )
+ return -EINVAL;
+
+ if ( !array_access_ok(op.gpfn_list, op.nr_gpfns, sizeof(*op.gpfn_list)) ||
+ !array_access_ok(op.mfn_list, op.nr_gpfns, sizeof(*op.mfn_list)) )
+ return -EFAULT;
-long do_memory_op(int cmd, void *arg)
+ if ( op.domid == DOMID_SELF )
+ op.domid = current->domain->domain_id;
+ else if ( !IS_PRIV(current->domain) )
+ return -EPERM;
+
+ if ( (d = find_domain_by_id(op.domid)) == NULL )
+ return -ESRCH;
+
+ if ( !shadow_mode_translate(d) )
+ {
+ put_domain(d);
+ return -EINVAL;
+ }
+
+ for ( i = *progress; i < op.nr_gpfns; i++ )
+ {
+ if ( hypercall_preempt_check() )
+ {
+ put_domain(d);
+ *progress = i;
+ return -EAGAIN;
+ }
+
+ if ( unlikely(__copy_from_user(&gpfn, &op.gpfn_list[i],
+ sizeof(gpfn))) )
+ {
+ put_domain(d);
+ return -EFAULT;
+ }
+
+ mfn = gmfn_to_mfn(d, gpfn);
+
+ if ( unlikely(__copy_to_user(&op.mfn_list[i], &mfn,
+ sizeof(mfn))) )
+ {
+ put_domain(d);
+ return -EFAULT;
+ }
+ }
+
+ put_domain(d);
+ return 0;
+}
+
+long do_memory_op(unsigned long cmd, void *arg)
{
struct domain *d;
- int rc, start_extent, op, flags = 0, preempted = 0;
+ int rc, op, flags = 0, preempted = 0;
+ unsigned long start_extent, progress;
struct xen_memory_reservation reservation;
domid_t domid;
if ( copy_from_user(&reservation, arg, sizeof(reservation)) )
return -EFAULT;
+ /* Is size too large for us to encode a continuation? */
+ if ( reservation.nr_extents > (ULONG_MAX >> START_EXTENT_SHIFT) )
+ return -EINVAL;
+
start_extent = cmd >> START_EXTENT_SHIFT;
if ( unlikely(start_extent > reservation.nr_extents) )
return -EINVAL;
break;
+ case XENMEM_translate_gpfn_list:
+ progress = cmd >> START_EXTENT_SHIFT;
+ rc = translate_gpfn_list(arg, &progress);
+ if ( rc == -EAGAIN )
+ return hypercall2_create_continuation(
+ __HYPERVISOR_memory_op,
+ op | (progress << START_EXTENT_SHIFT),
+ arg);
+ break;
+
default:
rc = arch_memory_op(op, arg);
break;
*/
#define XENMEM_reserved_phys_area 7
typedef struct xen_reserved_phys_area {
- /* Which request to report about? */
+ /* Which domain to report about? */
domid_t domid;
/*
unsigned long first_gpfn, nr_gpfns;
} xen_reserved_phys_area_t;
+/*
+ * Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error
+ * code on failure. This call only works for auto-translated guests.
+ */
+#define XENMEM_translate_gpfn_list 8
+typedef struct xen_translate_gpfn_list {
+ /* Which domain to translate for? */
+ domid_t domid;
+
+ /* Length of list. */
+ unsigned long nr_gpfns;
+
+ /* List of GPFNs to translate. */
+ unsigned long *gpfn_list;
+
+ /*
+ * Output list to contain MFN translations. May be the same as the input
+ * list (in which case each input GPFN is overwritten with the output MFN).
+ */
+ unsigned long *mfn_list;
+} xen_translate_gpfn_list_t;
+
#endif /* __XEN_PUBLIC_MEMORY_H__ */
/*